﻿using DeviceAlarmService.Models;
using DeviceAlarmService.SystemService;
using System.Text.Json;

namespace DeviceAlarmService.DeviceManagement.DeviceConnection;

public class DMS
{
    /// <summary>
    /// 操作委托
    /// </summary>
    /// <param name="status"></param>
    public delegate void LogDelegate(string log);
    /// <summary>
    /// 操作事件
    /// </summary>
    /// <param name="status"></param>
    public event LogDelegate LogEvent;
    /// <summary>
    /// 日志
    /// </summary>
    /// <param name="log"></param>
    public void OperationLog(string log)
    {
        if (LogEvent is not null)
        {
            LogEvent($"{log}");
        }
    }

    /// <summary>
    /// 操作委托
    /// </summary>
    /// <param name="status"></param>
    public delegate void ConnectionDisconnectedEventDelegate(string id);
    /// <summary>
    /// 操作事件
    /// </summary>
    /// <param name="status"></param>
    public event ConnectionDisconnectedEventDelegate CloseEvent;
    /// <summary>
    /// 操作事件
    /// </summary>
    /// <param name="status"></param>
    public event ConnectionDisconnectedEventDelegate RunningEvent;

    /// <summary>
    /// 在运行设备编号
    /// </summary>
    List<string> Running = new List<string>();

    /// <summary>
    /// 在运行列表
    /// </summary>
    public List<string> RunningId
    {
        get
        {

            return Running;
        }
    }

    /// <summary>
    /// 开启服务
    /// </summary>
    public void Open(string conf)
    {
        //配置文件序列化
        DeviceInformation deviceInformation = JsonSerializer.Deserialize<DeviceInformation>(conf)!;
        //检查设备是否在运行
        if (Running.Contains(deviceInformation.number) == false)
        {
            //开启新线程
            new Task(() =>
            {
                //启动设备服务
                //通过 通讯协议 序列化配置文件
                if (deviceInformation.protocol == Protocol.SiemensS7)
                {
                    OnTheDeviceSiemensS7(conf);
                }
                if (deviceInformation.protocol == Protocol.ModbusTcp)
                {
                    OnTheDeviceModbusTcp(conf);
                }
            }).Start();
        }
    }

    /// <summary>
    /// 关闭设备
    /// </summary>
    /// <param name="id"></param>
    public void Close(string id)
    {
        //检查关闭设备是否在运行
        if (Running.Contains(id))
        {
            //从在运行id list中删除
            Running.Remove(id);

            if (CloseEvent is not null)
            {
                CloseEvent(id);
            }
        }
    }

    /// <summary>
    /// 关闭所有服务
    /// </summary>
    public void CloseAll()
    {
        if (Running is not null && Running.Count >= 1)
        {
            //Running.Clear();
            //事件驱动
            foreach (var item in Running)
            {
                //从在运行id list中删除
                Running.Remove(item);

                if (CloseEvent is not null)
                {
                    CloseEvent(item);
                }
            }
        }
    }

    /// <summary>
    /// 开启设备
    /// </summary>
    private void OnTheDeviceSiemensS7(string conf)
    {
        //配置文件序列化
        Models.SiemensPlc.DeviceInformation device = JsonSerializer.Deserialize<Models.SiemensPlc.DeviceInformation>(conf)!;
        //报警地址列表
        SortedList<string, AlarmInformation> addrList = new();
        //获取数据地址
        List<Models.SiemensPlc.DataAddress> dataAddress = device.dataAddress;
        SiemensPlc.ConnectingObjects connectingObjects = new(device);
        ConnectionCheck connectionCheck = new();
        connectionCheck.IsIpEffective(device.deviceAddress.ip);

        try
        {
            //连接设备
            connectingObjects.Connect();
            //添加运行状态
            Running.Add(device.number);
            if (RunningEvent is not null)
            {
                RunningEvent(device.number);
            }
            OperationLog($"服务开启   编号：{device.number}   协议：{device.protocol}   设备：{device.name}");
            MessagePush.MessagePush messagePush = new();
            messagePush.LogEvent += OperationLog;
            while (true)
            {
                //检查运行权限 false 结束线程 || 检查是否存在数据地址 不存在则结束线程
                if (Running.Contains(device.number) == false || dataAddress.Count <= 0)
                {
                    OperationLog($"服务关闭   编号：{device.number}   协议：{device.protocol}   设备：{device.name}");
                    connectingObjects.Close();
                    break;
                }
                //检查连接状态
                if (connectingObjects.IsConnected == false)
                {
                    OperationLog($"服务关闭   编号：{device.number}   协议：{device.protocol}   设备：{device.name}   信息：设备连接断开！");
                    //连接断开 服务关闭
                    Close(device.number);
                    //启动重连事件
                    DisconnectAndReconnect(conf);
                    connectingObjects.Close();
                    break;
                }
                //获取报警状态
                List<bool> value = connectingObjects.ReadBool();
                //检查报警
                for (int i = 0; i < value.Count; i++)
                {
                    //检查是否启用报警 
                    if (dataAddress[i].isEnable == false)
                    {
                        continue;
                    }
                    //检查是否已经存在报警  存在报警
                    if (addrList.ContainsKey(dataAddress[i].alarmAddress))
                    {
                        //获取当前时间的时间戳（秒为单位）  
                        long timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
                        AlarmInformation alarmInformation = addrList[dataAddress[i].alarmAddress];
                        //报警间隔
                        if (alarmInformation.startTimestamp < timestamp)
                        {
                            //确认是否存在报警
                            if (value[i] == true)
                            {
                                //报警信息处理
                                //默认人员级别 为 1 管理 为 0 同一报警 2 次，一次管理报警
                                if (alarmInformation.count % 3 == 0)
                                {
                                    messagePush.Receive(device.contacts, device.name, dataAddress[i].alarmInformation, Level.Administration);
                                }
                                else
                                {
                                    messagePush.Receive(device.contacts, device.name, dataAddress[i].alarmInformation, Level.User);
                                }
                                //报警计数
                                alarmInformation.count++;
                                //重新赋值
                                alarmInformation.startTimestamp = DateTimeOffset.Now.ToUnixTimeSeconds() + ConfigService.Configuration.alarmInterval;
                            }
                            else
                            {
                                addrList.Remove(dataAddress[i].alarmAddress);
                            }
                        }
                    }
                    else if (value[i])
                    {
                        //添加新的报警
                        addrList.Add(dataAddress[i].alarmAddress, new()
                        {
                            uid = dataAddress[i].alarmAddress,
                            count = 2,
                            //获取当前时间的UTC时间戳（秒为单位）
                            startTimestamp = DateTimeOffset.Now.ToUnixTimeSeconds() + ConfigService.Configuration.alarmInterval
                        });
                        //报警通知
                        messagePush.Receive(device.contacts, device.name, dataAddress[i].alarmInformation, Level.User);
                    }
                }

                //采集频率 按秒计算
                Thread.Sleep(ConfigService.Configuration.collectionInterval * 1000);
            }
        }
        catch (Exception ex)
        {
            Close(device.number);
            connectingObjects.Close();
            OperationLog($"服务异常   编号：{device.number}   协议：{device.protocol}   设备：{device.name}   异常：{ex.Message}");
        }
        //服务结束
    }
    private void OnTheDeviceModbusTcp(string conf)
    {
        Models.ModbusTcp.DeviceInformation device = JsonSerializer.Deserialize<Models.ModbusTcp.DeviceInformation>(conf)!;
        //报警地址列表
        SortedList<string, AlarmInformation> addrList = new();
        //获取数据地址
        Models.ModbusTcp.DataAddress dataAddress = device.dataAddress;
        ModbusTcp.ConnectingObjects connectingObjects = new(device);
        ConnectionCheck connectionCheck = new();
        connectionCheck.IsIpEffective(device.deviceAddress.ip);
        try
        {
            //连接设备
            connectingObjects.Connect();
            //添加运行状态
            Running.Add(device.number);
            if (RunningEvent is not null)
            {
                RunningEvent(device.number);
            }
            OperationLog($"服务开启   编号：{device.number}协议：{device.protocol}   设备：{device.name}   ");
            MessagePush.MessagePush messagePush = new();
            messagePush.LogEvent += OperationLog;
            while (true)
            {
                //检查运行状态权限
                if (Running.Contains(device.number) == false || device.dataAddress.numberOfPoints < 1)
                {
                    OperationLog($"服务关闭   编号：{device.number}   协议：{device.protocol}   设备：{device.name}");
                    connectingObjects.Close();
                    break;
                }
                //获取报警状态
                List<bool> value = connectingObjects.ReadBool();

                //检查连接状态
                if (connectingObjects.IsConnected == false)
                {
                    OperationLog($"服务关闭   编号：{device.number}   协议：{device.protocol}   设备：{device.name}   信息：设备连接断开！");
                    //连接断开 服务关闭
                    Close(device.number);
                    connectingObjects.Close();
                    //启动重连事件
                    DisconnectAndReconnect(conf);
                    break;
                }
                //检查报警
                for (int i = 0; i < value.Count; i++)
                {
                    //检查是否启用报警 
                    if (dataAddress.isEnable[i] == false)
                    {
                        continue;
                    }
                    //检查是否已经存在报警  存在报警
                    if (addrList.ContainsKey(dataAddress.uid[i]))
                    {
                        //获取当前时间的时间戳（秒为单位）  
                        long timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
                        AlarmInformation alarmInformation = addrList[dataAddress.uid[i]];
                        //报警间隔
                        if (alarmInformation.startTimestamp < timestamp)
                        {
                            //确认是否存在报警
                            if (value[i] == true)
                            {
                                //报警信息处理
                                //默认人员级别 为 1 管理 为 0 同一报警 2 次，一次管理报警
                                if (alarmInformation.count % 3 == 0)
                                {
                                    messagePush.Receive(device.contacts, device.name, dataAddress.alarmInformation[i], Level.Administration);
                                }
                                else
                                {
                                    messagePush.Receive(device.contacts, device.name, dataAddress.alarmInformation[i], Level.User);
                                }
                                //报警计数
                                alarmInformation.count++;
                                //重新赋值
                                alarmInformation.startTimestamp = DateTimeOffset.Now.ToUnixTimeSeconds() + ConfigService.Configuration.alarmInterval;
                            }
                            else
                            {
                                addrList.Remove(dataAddress.uid[i]);
                            }
                        }
                    }
                    else if (value[i] == true)
                    {
                        //添加新的报警
                        addrList.Add(dataAddress.uid[i], new()
                        {
                            uid = dataAddress.uid[i],
                            count = 2,
                            //获取当前时间的UTC时间戳（秒为单位）
                            startTimestamp = DateTimeOffset.Now.ToUnixTimeSeconds() + ConfigService.Configuration.alarmInterval
                        });
                        //报警通知
                        messagePush.Receive(device.contacts, device.name, dataAddress.alarmInformation[i], Level.User);
                    }
                }
                Thread.Sleep(ConfigService.Configuration.collectionInterval * 1000);
            }
        }
        catch (Exception ex)
        {
            OperationLog($"服务异常   编号：{device.number}协议：{device.protocol}   设备：{device.name}   异常：{ex.Message}");
            connectingObjects.Close();
            Close(device.number);
        }
    }

    /// <summary>
    /// 断线重连服务
    /// </summary>
    private void DisconnectAndReconnect(string conf)
    {
        new Task(() =>
        {
            //断线重连服务

            //配置文件序列化
            DeviceInformation deviceInformation = JsonSerializer.Deserialize<DeviceInformation>(conf)!;
            OperationLog($"服务异常   编号：{deviceInformation.number}协议：{deviceInformation.protocol}   设备：{deviceInformation.name}   信息：设备正在尝试断线重连服务！");
            //通过 通讯协议 序列化配置文件
            if (deviceInformation.protocol == Protocol.SiemensS7)
            {
                //配置文件序列化
                Models.SiemensPlc.DeviceInformation device = JsonSerializer.Deserialize<Models.SiemensPlc.DeviceInformation>(conf)!;
                SiemensPlc.ConnectingObjects connectingObjects = new(device);
                ConnectionCheck connectionCheck = new();
                connectionCheck.IsIpEffective(device.deviceAddress.ip);
                try
                {
                    //是否成功
                    bool isSuccess = false;
                    //尝试3次重连
                    for (int i = 1; i <= 3; i++)
                    {
                        //连接设备
                        OperationLog($"服务异常   编号：{deviceInformation.number}协议：{deviceInformation.protocol}   设备：{deviceInformation.name}   信息：尝试断线重连服务第：{i}次！");
                        connectingObjects.Connect();

                        if (connectingObjects.IsConnected)
                        {
                            OperationLog($"服务通知   编号：{deviceInformation.number}协议：{deviceInformation.protocol}   设备：{deviceInformation.name}   信息：尝试断线重连服务第：{i}次，重连服务成功，尝试开启服务！");
                            isSuccess = true;
                            break;
                        }
                        //每次重连服务间隔15秒
                        Thread.Sleep(15 * 1000);
                    }
                    if (isSuccess)
                    {
                        OnTheDeviceSiemensS7(conf);
                    }
                    else
                    {
                        OperationLog($"服务通知   编号：{deviceInformation.number}协议：{deviceInformation.protocol}   设备：{deviceInformation.name}   信息：尝试断线重连服务第：3次，重连服务失败，服务已经自动关闭，请尝试手动重新开启服务！");
                    }
                }
                catch (Exception ex)
                {
                    OperationLog($"服务异常   编号：{deviceInformation.number}协议：{deviceInformation.protocol}   设备：{deviceInformation.name}   信息：{ex.Message}");
                }

            }
            if (deviceInformation.protocol == Protocol.ModbusTcp)
            {
                Models.ModbusTcp.DeviceInformation device = JsonSerializer.Deserialize<Models.ModbusTcp.DeviceInformation>(conf)!;
                ModbusTcp.ConnectingObjects connectingObjects = new(device);
                ConnectionCheck connectionCheck = new();
                connectionCheck.IsIpEffective(device.deviceAddress.ip);
                try
                {
                    //是否成功
                    bool isSuccess = false;
                    //尝试3次重连
                    for (int i = 1; i <= 3; i++)
                    {
                        //连接设备
                        OperationLog($"服务异常   编号：{deviceInformation.number}协议：{deviceInformation.protocol}   设备：{deviceInformation.name}   信息：尝试断线重连服务第：{i}次！");
                        connectingObjects.Connect();

                        if (connectingObjects.IsConnected)
                        {
                            OperationLog($"服务通知   编号：{deviceInformation.number}协议：{deviceInformation.protocol}   设备：{deviceInformation.name}   信息：尝试断线重连服务第：{i}次，重连服务成功，尝试开启服务！");
                            isSuccess = true;
                            break;
                        }
                        //每次重连服务间隔15秒
                        Thread.Sleep(15 * 1000);
                    }
                    if (isSuccess)
                    {
                        OnTheDeviceModbusTcp(conf);
                    }
                    else
                    {
                        OperationLog($"服务通知   编号：{deviceInformation.number}协议：{deviceInformation.protocol}   设备：{deviceInformation.name}   信息：尝试断线重连服务第：3次，重连服务失败，服务已经自动关闭，请尝试手动重新开启服务！");
                    }
                }
                catch (Exception ex)
                {
                    OperationLog($"服务异常   编号：{deviceInformation.number}协议：{deviceInformation.protocol}   设备：{deviceInformation.name}   信息：{ex.Message}");
                }

            }
        }).Start();
    }
}